home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / processes / sharedmemory / sharedmemory.m < prev   
Encoding:
Text File  |  2000-10-06  |  10.6 KB  |  240 lines

  1. /*
  2.     File:        SharedMemory.m
  3.  
  4.     Contains:    A sample to demonstrate Shared Memory using shmget()
  5.  
  6.     Written by:     Karl Groethe
  7.  
  8.     Copyright:    Copyright © 2000 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.             You may incorporate this Apple sample source code into your program(s) without
  11.             restriction. This Apple sample source code has been provided "AS IS" and the
  12.             responsibility for its operation is yours. You are not permitted to redistribute
  13.             this Apple sample source code as "Apple sample source code" after having made
  14.             changes. If you're going to re-distribute the source, we require that you make
  15.             it clear in the source that the code was descended from Apple sample source
  16.             code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                         8/16/00        Created
  20. */
  21. #import "SharedMemory.h"
  22.  
  23. #include <sys/shm.h>
  24. #include <sys/errno.h>
  25.  
  26. //access permissions on our memory 0666=everyone can access
  27. #define GLOBAL_PERMISSIONS 0666
  28.  
  29. //error strings
  30. #define EUNKNOWN_STR "Unknown Error occured"
  31. #define ENOSPC_STR "All possible shared memory IDs are allocated"
  32. #define ENOMEM_STR "allocating requested size would exceed the limit on shared memory"
  33. #define EACCES_STR "You do not have access permission"
  34. #define EINVAL_STR "Invalid segment size specified"
  35. #define EINVAL_STR2 "Not a valid memory identifier"
  36. #define EMFILE_STR "The number of shared memory segments has reached it's limit"
  37.  
  38. @implementation SharedMemory
  39.  
  40. -(id)init
  41. {
  42.     /*------------------------------------------------------
  43.       do initialization
  44.     --------------------------------------------------------*/
  45.     if(self=[super init])
  46.     {
  47.         SemaphoreID=NULL;
  48.         //catch thread terminations form our update thread
  49.         [[NSNotificationCenter defaultCenter] addObserver:self
  50.                                               selector:@selector(FinishedUpdate:)
  51.                                               name:NSThreadWillExitNotification 
  52.                                               object:nil];
  53.         
  54.     }
  55.     return self;
  56. }
  57.  
  58. -(void)dealloc
  59. {
  60.     /*------------------------------------------------------
  61.         do cleanup
  62.     --------------------------------------------------------*/
  63.     if([[AttachDetach  title] compare:@"Detach"]==NSOrderedSame)//if we're attached
  64.         [self AttachDetach:self];    //make sure we've detached from our shared memory
  65.     sem_close(SemaphoreID);        //close our semaphore
  66.     [super dealloc];
  67. }
  68. -(void)FinishedUpdate :(id)anObject
  69. {
  70.     /*------------------------------------------------------
  71.        Notification that our thread has finished
  72.     --------------------------------------------------------*/
  73.     if([[AttachDetach  title] compare:@"Detach"]==NSOrderedSame)//if we're attached to shared memory
  74.         //spin off thread to display the stats
  75.         [NSThread detachNewThreadSelector:@selector(UpdateSharedMemoryDisplay) toTarget:self
  76.                                         withObject:self];
  77. }
  78.  
  79. - (void)AttachDetach:(id)sender
  80. {
  81.     /*------------------------------------------------------
  82.         Create, attach, or detach from shared memory segment
  83.     --------------------------------------------------------*/
  84.     if([[AttachDetach  title] compare:@"Create/Attach"]==NSOrderedSame)//if we're attaching/creating
  85.     {
  86.         int key=[Key intValue];//Get the key from the key field
  87.         int size=[BlockSize intValue];//Get the size from the size field
  88.         //use shmget with our key, size and options, IPC_CREAT specified create if non-existant
  89.         SharedMemID=shmget(key,size,IPC_CREAT | GLOBAL_PERMISSIONS);
  90.         //check for errors
  91.         if(SharedMemID==-1){
  92.             char* errorStr=NULL;
  93.             switch(errno){
  94.                 case ENOSPC: errorStr=ENOSPC_STR;break;
  95.                 case ENOMEM: errorStr=ENOMEM_STR;break;
  96.                 case EACCES: errorStr=EACCES_STR;break;
  97.                 case EINVAL: errorStr=EINVAL_STR;break;
  98.                 default:     errorStr=EUNKNOWN_STR;
  99.             }
  100.             NSRunAlertPanel(@"An Error Occured with shmget()",
  101.                             @"Unable to Get memory associated with key: %i\n %s\nError# %i",
  102.                             @"OK",nil,nil,key,errorStr,errno);
  103.             return;
  104.         }
  105.         //Grab a pointer to our shared memory with shmat() using the ID returned from shmget()
  106.         SharedMemoryBlock=shmat(SharedMemID,0,GLOBAL_PERMISSIONS);
  107.         //test for errors
  108.         if(SharedMemoryBlock==NULL){
  109.             char* errorStr=NULL;
  110.             switch(errno){
  111.                 case EACCES: errorStr=EACCES_STR;break;
  112.                 case ENOMEM: errorStr=ENOMEM_STR;break;
  113.                 case EINVAL: errorStr=EINVAL_STR2;break;
  114.                 case EMFILE: errorStr=EMFILE_STR;break;
  115.                 default:     errorStr=EUNKNOWN_STR;
  116.             }
  117.             NSRunAlertPanel(@"An Error occured with shmat()",
  118.                             @"Unable to Access memory associated with key: %i\n %s \nError# %i",
  119.                             @"OK",nil,nil,key,errorStr,errno);
  120.             return;
  121.         }
  122.         //if our semaphore exists then close it.
  123.         if(SemaphoreID) sem_close(SemaphoreID);
  124.         
  125.         //create a named semaphore using a string version of our key to identify it.
  126.         SemaphoreID=sem_open([[NSString stringWithFormat:@"%i",key] cString],
  127.                                 O_CREAT,GLOBAL_PERMISSIONS,1);
  128.         //check for errors
  129.         if((int)SemaphoreID==SEM_FAILED){
  130.             NSRunAlertPanel(@"An Error Occured with sem_open()",@"",@"OK",NULL,NULL);
  131.             shmdt(SharedMemoryBlock);
  132.             return;
  133.         }
  134.         //update our interface to show that we are attached to a shared memory segment
  135.         [AttachDetach setTitle:@"Detach"];
  136.         [Key setEditable:FALSE];
  137.         [BlockSize setEditable:FALSE];
  138.         [Data setEditable:FALSE];
  139.         [[Data window] makeFirstResponder:[Data window]];
  140.         [StartStopButton setEnabled:TRUE];
  141.         //spin off an update thread
  142.         [NSThread detachNewThreadSelector:@selector(UpdateSharedMemoryDisplay) toTarget:self
  143.                                         withObject:self];
  144.     }else{//we are attached so detach
  145.         struct shmid_ds SharedMemDS;
  146.         //If editing semaphore is set then stop editing
  147.         if([[StartStopButton title] compare:@"Stop Editing"]==NSOrderedSame)//
  148.             [self StartStopEditing:self];
  149.         //detach from our shared memory
  150.         shmdt(SharedMemoryBlock);
  151.         //get stats for shared memory segment
  152.         shmctl(SharedMemID,IPC_STAT,&SharedMemDS);
  153.         if(SharedMemDS.shm_nattch==0)//if nobody is attached anymore
  154.             //remove the segment so the key  and memory can be reused
  155.             shmctl(SharedMemID,IPC_RMID,NULL);
  156.         //update interface
  157.         [StartStopButton setEnabled:FALSE];
  158.         [AttachDetach setTitle:@"Create/Attach"];
  159.         [Key setEditable:TRUE];
  160.         [Key setStringValue:@""];
  161.         [BlockSize setEditable:TRUE];
  162.         [BlockSize setStringValue:@""];
  163.     }
  164. }
  165. -(void)StartStopEditing:(id)sender
  166. {
  167.     /*------------------------------------------------------
  168.        make the shared memory field editable or not editable
  169.        and set the semaphore.
  170.     --------------------------------------------------------*/
  171.     //if the user clicked start editing
  172.     if([[StartStopButton title] compare:@"Start Editing"]==NSOrderedSame)//
  173.     {
  174.         if(sem_trywait(SemaphoreID)!=-1){//try to get a lock on our semaphore
  175.             //update interface to allow editing shared memory
  176.             [StartStopButton setTitle:@"Stop Editing"];
  177.             [Data setEditable:TRUE];
  178.             [[Data window] makeFirstResponder:Data];
  179.             [Data moveToBeginningOfDocument:self];
  180.         }else//semaphore already set so put up alert
  181.            NSRunAlertPanel(@"Semaphore Already Set",
  182.                            @"Cannot Edit memory until the semaphore is released",
  183.                            @"OK",nil,nil);
  184.     }else{//stop editing was clicked
  185.         NSRange charRange={0,[BlockSize intValue]};
  186.         //update interface to not allow edting shared memory
  187.         [StartStopButton setTitle:@"Start Editing"];
  188.         [Data setEditable:FALSE];
  189.         [[Data window] makeFirstResponder:[Data window]];
  190.         //copy the string from our text field to the shared memory
  191.         [[Data string] getCharacters:(unichar*)SharedMemoryBlock range:charRange];
  192.         //release semaphore
  193.         sem_post(SemaphoreID);
  194.     }
  195.         
  196. }
  197. -(void)UpdateSharedMemoryDisplay
  198. {
  199.     /*------------------------------------------------------
  200.        Thread to update display of stats for shared memory
  201.        segment
  202.     --------------------------------------------------------*/
  203.     //since we're in a thread we need to allocate our own AutoreleasePool
  204.     NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
  205.     struct shmid_ds SharedMemDS;
  206.     //get shared memory stats
  207.     if(shmctl(SharedMemID,IPC_STAT,&SharedMemDS)!=-1){
  208.         //update Size field
  209.         [BlockSize setIntValue:SharedMemDS.shm_segsz];
  210.         //update number of attaches field
  211.         [NumberOfAttaches setIntValue:SharedMemDS.shm_nattch];
  212.         //update Creator field
  213.         [Creator setIntValue:SharedMemDS.shm_cpid];
  214.         //update Last Operator feild
  215.         [Operator setIntValue:SharedMemDS.shm_lpid];  
  216.         //update Last Attach time field formatted as hour:min:sec    
  217.         [AttachTime setStringValue:[[NSDate dateWithTimeIntervalSince1970:
  218.                                     SharedMemDS.shm_atime] descriptionWithCalendarFormat:@"%H:%M:%S" 
  219.                                     timeZone:nil locale:nil]];
  220.         //update Last Change time field formatted as hour:min:sec                              
  221.         [ChangeTime setStringValue:[[NSDate dateWithTimeIntervalSince1970:
  222.                                     SharedMemDS.shm_ctime] descriptionWithCalendarFormat:@"%H:%M:%S" 
  223.                                     timeZone:nil locale:nil]];
  224.         //update Last Change time field formatted as hour:min:sec  
  225.         [DetachTime setStringValue:[[NSDate dateWithTimeIntervalSince1970:
  226.                                     SharedMemDS.shm_dtime] descriptionWithCalendarFormat:@"%H:%M:%S" 
  227.                                     timeZone:nil locale:nil]];
  228.         if((sem_trywait(SemaphoreID)!=-1)){//see if we can update shared memory string
  229.             [Data setString:[NSString stringWithCharacters:(const unichar*)SharedMemoryBlock
  230.                                                                 length:[BlockSize intValue]-1]];
  231.             sem_post(SemaphoreID);//release semaphore
  232.         }
  233.                 
  234.     }
  235.     [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];//sleep for a sec
  236.     [pool release];//free any temporary allocated objects
  237. }
  238.      
  239. @end
  240.